package org.computate.tool;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.computate.model.dao.ComputateDao;
import org.computate.model.dao.Daos;
import org.computate.model.item.Model;

import com.google.inject.Inject;

public class ModelToolImpl implements ModelTool {
	
	@Inject Daos daos;
	
	@SuppressWarnings("unchecked")
	public Class<? extends Model> getClass(String modelName) {
		Class<? extends Model> result = null;

		if (modelName != null) {
				try {
					Class<?> c = Class.forName("org.computate.model.item." + modelName);
					if (c != null && Model.class.isAssignableFrom(c)) {
						result = (Class<? extends Model>)c;
					}
				} catch (ClassNotFoundException e) {
					// ignore
				}
		}

		return result;
	}
	
	public Class<?> getDaoClass(String modelName) {
		Class<?> result = null;
		
		if(modelName != null) {
			try {
				result = Class.forName("org.computate.model.dao." + modelName + "Dao");
			} catch (ClassNotFoundException e) {
				// return null
			}
		}
		
		return result;
	}
	
	public ComputateDao<?> getDao(String modelName) {
		return daos.getDao(modelName);
	}
	
	public Model getItem(ComputateDao<?> dao, Long id, int getLevels) {
		Model result = null;
		
		if(dao != null && id != null) {
			result = dao.get(id, getLevels);
		}
		
		return result;
	}
	
	public Class<?> getItemClass(String modelName) {
		Class<?> result = null;
		
		if(modelName != null) {
			try {
				result = Class.forName("org.computate.model.item." + modelName);
			} catch (ClassNotFoundException e) {
				// return null
			}
		}
		
		return result;
	}
	
	public void edit(String fieldName, Class<?> c, Model item, String valueString, ComputateDao<?> dao) {
		if(!StringUtils.isEmpty(fieldName) && c != null && item != null && dao != null) {
			try {
				PropertyDescriptor propertyDescriptor = new PropertyDescriptor(fieldName, c);
				Method setter = propertyDescriptor.getWriteMethod();
				Class<?> fieldClass = propertyDescriptor.getReadMethod().getReturnType();
				
				if(fieldClass.equals(String.class)) {
					setter.invoke(item, valueString);
				}
				else if(fieldClass.equals(Boolean.class) || fieldClass.equals(boolean.class)) {
					Boolean value = BooleanUtils.toBoolean(valueString);
					
					setter.invoke(item, value);
				}
				else if(fieldClass.equals(Integer.class) || fieldClass.equals(int.class)) {
					Integer value = NumberUtils.toInt(valueString);
					
					setter.invoke(item, value);
				}
				else if(fieldClass.equals(Long.class) || fieldClass.equals(long.class)) {
					Long value = NumberUtils.toLong(valueString);
					
					setter.invoke(item, value);
				}
				else if(fieldClass.equals(Date.class)) {
					Date value = DateUtils.parseDate(valueString, "yyyy-MM-dddd");
					
					setter.invoke(item, value);
				}
				
				dao.save(item);
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IntrospectionException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public Model add(HttpServletRequest request, HttpServletResponse response, String modelName, String name) throws InstantiationException, IllegalAccessException {
		Class<?> itemClass = getItemClass(modelName);
		ComputateDao<?> dao = getDao(modelName);
		String parentField = request.getParameter("parentField");
		String parentIdParam = request.getParameter("parentId");
		Long parentId = NumberUtils.toLong(parentIdParam);
		Model newInstance = (Model)itemClass.newInstance();
		Model item = null;
		
		if(parentId != null && !StringUtils.isEmpty(parentField))
			item = dao.create(name, parentField, parentId, newInstance.getGetLevels());
		else
			item = dao.create(name);
		
		request.setAttribute("modelName", modelName);
		request.setAttribute("modelDisplayName", newInstance.getModelDisplayName());
		request.setAttribute("modelPluralName", newInstance.getModelPluralName());
		request.setAttribute("item", item);
		
		return item;
	}
}
